#!/bin/bash
######################################
## backup_vmware.sh 
## "stable" version 3.12b (07-08-2009)
##
##  backup_vmware copyright (C)  2009  Michele Pensotti - gcanavralla@yahoo.it
##  This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
##  This is free software, and you are welcome to redistribute it
##  under certain conditions; type `show c' for details.
##

######################################
## backup_vmware , a bash script to backup VmWare guests running on a linux host
##  uses the following strategies
## "hot backup" : vmware snapshot VM -> (optional LVM snapshot)  ->  backup of the VM files (optionally from the LVM snapshot) -> (optionally remove LVM snapshot)
## "cold backup" : vmware suspend VM -> (optional LVM snapshot) -> backup of the VM files (optionally from the LVM snapshot) -> (optionally remove LVM snapshot)
## 1) this script was created with VmWare Server 1.0.x in mind and was entirely developed on Debian Etch and Centos 5.2 hosts, thus I make no guarantees
##	that it will work on different Linux OS and with different VmWare Server versions
## NOTE: the script has now been re-written to work with VMware Server 2.0.x too, but with some limitations (see point n. 4 below )
## 2) requires the sendEmail script for the sending of email with the backup status
## 	in Debian Etch it's necessary to install the "sendemail" package
## 3) if the LVM option is enabled, the VM guests need to reside on a LVM2 logical volume and its volume group 
##	*MUST* have some free physical extents or the LVM snapshot won't be possible
## 4) If used with VMware Server 2.0.x please note that only the "[standard]" datastore will be considered by the script
######################################

######################## DO NOT TOUCH ANYTHING BELOW THIS LINE!! ###############################
#
# ALL THE VARIABLES ARE INITIALIZED

# CURRENTPATH is the path where the script is being and must be a writable path 
CURRENTPATH="$( pwd )"

##############################
# STATUS VARIABLES AND FLAGS (initialization)
# all the variables that will (or might) be used in the script are emptied
##############################
# DEBUG if it's set to 1 will enable the detailed console logging
DEBUG=""
# SUSPEND contains the result of the VM suspend operation (actually unused)
SUSPEND=""
# SUSPSTATUS contains the VM suspend status before starting (actually unused)
SUSPSTATUS=""
# PWRSTATUS contains the VM power status (on or off)
PWRSTATUS=""
# SNAPSHOT contains the exit status of the snapshot operation, it will be "OK" if no errors and "ERRORE" if there have been errors
SNAPSHOT=""
# COPYSTATUS (actually unused)
COPYSTATUS=""
# RESTART contains "YES" the VM needs to be restarted (if it was powered ON before, then it will be restarted)
RESTART=""
# RESTARTSTATUS (actually unused)
RESTARTSTATUS=""
# GUESTERROR contains the space separated list of the VMs that have had errors and weren't properly backed up
GUESTERROR=""
# GUESTOK contains the space separated list of the VMs that have been correctly backed up
GUESTOK=""
# THISGUESTOK is a flag containing the current VM backup status, and if it was backed up correctly it will contain "TRUE"
THISGUESTOK=""
# RESULT contains the abbreviated status of the backup operation: it can have 3 values
# "backup completed" , backup with errors" , "backup failed"
RESULT=""
# NOSUSPEND is a flag that if set, will disable the suspend-fallback in case the snapshots fail
NOSUSPEND=""
# GUESTNAME will contain the names of the VM to backup
GUESTNAME=""
# GUESTCONF will contain the paths to the single .VMX files
GUESTCONF=""
# GUESTVMX will contain the names of the .VMX files without the path
GUESTVMX=""
# ARCHIVETYPE sets the type of archive to create
# don't set this option here since it will be set by the -f parameter on the command line!
ARCHIVETYPE=""
# ARCHIVECMD will contain the archiver's command line to be executed when the backup takes place
ARCHIVECMD=""

##############################
# VMWARE SERVER VERSION
##############################
# VMVERSION contains the version of VMware Server installed, can be 1 or 2 (or it contains ERROR if the version can't be correctly identified)
VMVERSION=""
VERSTR=$(vmrun | grep "vmrun version" | awk '{ print $3 }')
VMVERSION=$(echo $VERSTR | awk '{ split($1, a, "."); ver=a[1]"."a[2]a[3]; if (ver >= 1 && ver < 2) print "1"; else if (ver >= 2 && ver < 3) print "2"; else print "ERROR" }')
echo "\$VMVERSION = ""$VMVERSION"

##############################
function setmylang {
	if [ "$1" == "" ]; then
		printf "no language has been specified\n"
		printf "supply language as either \"en\" or \"it\" \n"
		printf "otherwise you can omit the --lang parameter\n"
		printf "and the script will revert to english\n"
		exit 0
	elif [ "$1" == "en" -o "$1" == "it" ]; then
		MYLANG="$1"
	else
		printf "unknown value for language option\n"
		printf "supply language as either \"en\" or \"it\" \n"
		printf "otherwise you can omit the --lang parameter\n"
		printf "and the script will revert to english\n"
		exit 0
	fi
}

##############################
# LOAD CONFIGURATION PARAMETERS FROM THE CONFIGURATION FILE (backup_vmware.conf)
# NOTE: if the file doesn't exist , stop the script
##############################
if [ -e "$CURRENTPATH"/backup_vmware.conf ]; then
	source "$CURRENTPATH"/backup_vmware.conf
else
	echo "The configuration file is not present, cannot continue "
	echo "please ensure that the \"backup_vmware.conf\" file is " 
	echo "present in the same directory of this script "
	exit 1
fi

##############################
# ENABLE BASH "pipefail" option
##############################
set -o pipefail

##############################
# PARSE COMMAND LINE PARAMETERS AND OPTIONS
# USEFUL FUNCTIONS
##############################
function now {
	date "+%Y-%m-%d [%k:%M:%S]"
}

function trim () {
	myvar="$1"
	myvar_trimmed=$(echo "$myvar" | sed 's/^ *//;s/ *$//')
	echo "$myvar_trimmed"
}

##############################
# this function searches all elements in an array to match a given string
# it returns code 42 if there's a match
function bash__is_in_array () {
	haystack=( "$@" )
	haystack_size=( "${#haystack[@]}" )
	needle=${haystack[$((${haystack_size}-1))]}
	for ((i=0;i<$(($haystack_size-1));i++)); do
		h="${haystack[${i}]}";
		[ "$h" == "$needle" ] && return 42
	done
}

##############################
# this function parses one single line output of the command vmware-vim-cmd vmsvc/getallvms
# and converts it into an array of 4 elements: VMID , VMNAME , DATASTORE , VMPATH
function getallvms_to_vminfo () {
	OLDIFS="$IFS"
	unset IFS
	##MYVAR="48     Virtual Machine sar cazz fors [standard] Virtual Machine/Virtual Machine.vmx         dosGuest        vmx-04"
	line="$1"

# split the string using space as the separator and return an array of n elements
##array=( $(echo $MYVAR | awk '{split($0,a," "); for (i=1; i<=NF; i++) print (a[i])}') )
	array=( $(echo "$line" | awk '{split($0,a," "); for (i=1; i<=NF; i++) print (a[i])}') )
	array_size=${#array[*]}

# let's start an if/then cycle which will identify the parts of the string
# the first part will always be the VM id, so i = 0
	n=0
	VMID="${array[$n]}"
	# echo "$VMID"
	# the following part should be the VM name, but it could contain spaces, so we go step by step, now i=1
	# let's increment the counter because we must check *after* the VM name to see if there's a square bracket
	n=$(expr $n + 1); 
	VMNAME=""

	until [[ $(echo "${array[$n]}" | grep -e "^\[" -e "[a-z]]$") ]]; do
		##echo "the $i element is NOT the datastore"
		# ok, now we know that $i element of the array is part of the VM name, so let's add it to the VMNAME variable
		VMNAME="$VMNAME""${array[$n]}"" "
		n=$(expr $n + 1);
	done
	# let's remove the trailing space from the variable
	VMNAME=$(trim "$VMNAME")

	# echo "the VM id is $VMID"
	# echo "the VM name is $VMNAME"
	# echo "the $n element is the datastore"
	local DATASTORE="${array[$n]}"
	# echo "the DATASTORE is ${array[$n]}"

	# ok now we got VMID , VMNAME and DATASTORE , we need "only" the VMPATH
	n=$(expr $n + 1); # we must check *after* the DATASTORE to see if it ends with ".vmx"
	VMPATH=""

	until [[ $(echo "${array[$n]}"  | grep -e "\.vmx$") ]]; do
		##echo "the $i element is NOT the last of VMPATH"
		# ok, now we know that $i element of the array is part of the VMPATH, so let's add it to the VMPATH variable
		VMPATH="$VMPATH""${array[$n]}"" "
		n=$(expr $n + 1);
	done
	VMPATH="$VMPATH""${array[$n]}"
	VMPATH=$(trim "$VMPATH")
	#echo "the VMPATH is $VMPATH"

	# ok now we've got our variables so let's stick those into a new VMINFO array
	declare -a VMINFO
	VMINFO=( "$VMID" "$VMNAME" "$DATASTORE" "$VMPATH" )
	echo "${VMINFO[0]}","${VMINFO[1]}","${VMINFO[2]}","${VMINFO[3]}"
	IFS="$OLDIFS"
}

##################
function getallreggedvms {
	## ok, let's run the command and then put it into an array (another!) separated by commas
	IFS="$(echo -e "\n\r")"
	REGGED_VMS=$(for vm in $($VIMCMD -U $VMUSER -P $VMPASS vmsvc/getallvms | grep ^[0-9]) ; do echo -e $vm ; done)
	declare -a VMARR
	VMARR=( $REGGED_VMS )
	VMNUM=${#VMARR[*]}
	#echo $VMARR
	IFS="\ "	

	# print out a listing of all registered VMs, with the single fields separated by commas
	#echo -e "on this server are currently registered the following VMs\n"
	##echo -e "the following "$VMNUM" VMs are registered in the [$DATASTORE] datastore \n"
	for ((k=0;k<"$VMNUM";k++)); do
		getallvms_to_vminfo "${VMARR[$k]}"
	done
	unset IFS
}

##################
## an improvement of example 2, it gets the string [datastore]/vmpath/ and finds out the id of the VM
## if the VM is not regged it will return error code 45
# VMFOUND is a flag that gets set to true only if the VM is found
function getvmid_from_datastore_vmpath {
	local VMFOUND=""
	IFS="$(echo -e "\n\r")"
	REGGED_VMS=$(for vm in $($VIMCMD -U $VMUSER -P $VMPASS vmsvc/getallvms | grep ^[0-9]) ; do echo -e $vm ; done)
	declare -a VMARR
	VMARR=( $REGGED_VMS )
	VMNUM=${#VMARR[*]}
	IFS="\ "

	j="$1"
	declare -a VMINFO
	for ((k=0;k<"$VMNUM";k++)); do
		IFS="$(echo -e "\,")"
		VMINFO=( $(getallvms_to_vminfo "${VMARR[$k]}") )
		DIRNAME=$(dirname $(echo "${VMINFO[3]}"))
		VMPATH="${VMINFO[2]}"/"$DIRNAME"
		if [ "$j" == "$VMPATH" ]; then
			echo "${VMINFO[0]}"
			VMFOUND="TRUE"
		else 
			true
		fi
	done
	if [ "$VMFOUND" == "TRUE" ]; then
		return 0
	else
		return 45
	fi
	unset IFS
}

##################
## this function gets the .vmx file location of a given VM id
## vmware-vim-cmd vmsvc/get.config 32 | grep -i vmpathname
## if the VM is not regged it will return error code 46
function getvmx_from_vmid {
	# first check if the ID is registered
	local IDFOUND=""
	local REGGED_VMS=$( getallreggedvms )
	declare a_REGGED_VMS
	IFS="$(echo -e "\n\r")"
	a_REGGED_VMS=( $(echo "$REGGED_VMS") )
	local i
	local THISVM
	local VMID
	local VMX
	declare a_THISVM
	declare a_VMX
	for ((i=0;i<${#a_REGGED_VMS[*]};i++)); do
		THISVM="${a_REGGED_VMS[$i]}"
		OLDIFS="$IFS"
		IFS=","
		a_THISVM=( $(echo "$THISVM") )
		IFS="$OLDIFS"
		VMID="${a_THISVM[0]}"
		if [ "$VMID" == "$1" ]; then
			IDFOUND="TRUE"
			# now let's get the vmx from the VMid
			VMX=$($VIMCMD -U $VMUSER -P $VMPASS vmsvc/get.config $VMID | grep -i "vmpathname")
			IFS="\""
			a_VMX=( $(echo "$VMX") )
			echo "${a_VMX[1]}"
		else
			IDFOUND="FALSE"
		fi
	done
	if [ "$IDFOUND" == "FALSE" ]; then
		return 46
	fi
	unset IFS
}

##############################
function vmdir_to_id {
	## SUPERSEDED BY getvmid_from_datastore_vmpath
	# this function returns the VM id of a given VM directory
	# 0 - check if the parameter is empty
	# 1 - check if it's an existing directory
	# 2 - check if the VM is registered 
	# 3 - get the id of the VM by matching it with the list of VM ids ( vmware-vim-cmd vmsvc/getallvms )
	# TO DO!
	exit 0
}

##############################
function listvm {
	if ([ "$1" == "" ] || [ "$1" == "long" ]); then
		LISTING="long"
	elif [ "$1" == "short" ]; then
		LISTING="short"
	else
		LISTING="long"
	fi

	## depending on which version of vmware server is installed, the method to retrieve
	## the currently registered VMs is different
	## for VMware version 1.x the command "vmware-cmd -l" is used
	## for VMware version 2.x the /etc/vmware/hostd/vmInventory.xml file can be parsed
	## OR the vmware-vim-cmd commands need to be called
	## for example: vmware-vim-cmd vmsvc/getallvms
	## ORthe vmrun need to be called
	## for example: vmrun -T server -h https://127.0.0.1:8333/sdk -u vmbackup -p vmbackup listRegisteredVM

	if [ "$VMVERSION" == "1" ]; then
		IFS="$(echo -e "\n\r")"
		## let's try to avoid using the vmware-cmd command since it may give some problems
		## instead we can use the /etc/vmware/vm-list file , adequately parsed by grep and sed
		REGGED_VMS=$(for i in $(grep -v ^# /etc/vmware/vm-list); do echo -e $i | sed -e 's/config //g' | sed -e 's/"//g'; done)
		#REGGED_VMS=$(for i in $($VMCMD -l) ; do echo -e $i ; done)
		declare -a VMARR
		VMARR=( $REGGED_VMS )
		VMNUM=${#VMARR[*]}
		IFS="\ "
		if [ "$LISTING" == "long" ]; then
			echo -e "the following ""$VMNUM"" VMs are registered \n"
			echo "$REGGED_VMS"
		fi
		# set the variable to 0 before starting the count
		ENABVMNUM=0
	
		for ((i=0;i<"$VMNUM";i++)); do
			THISVM="$(dirname "$( echo -e "${VMARR["$i"]}")")"
			if [ -e "$THISVM/.backup" ]; then
				##echo -e "${VMARR["$i"]}"
				ENABVMNUM=$[ENABVMNUM+1]
			fi
		done
		if [ "$LISTING" == "long" ]; then
			echo -e "\r"
			echo -e "the following ""$ENABVMNUM"" VMs are enabled for backup \n" 	
		fi
		for ((i=0;i<"$VMNUM";i++)); do
			THISVM="$(dirname "$( echo -e "${VMARR["$i"]}")")"
			if [ -e "$THISVM/.backup" ]; then
				echo -e "$THISVM"
			fi
		done
		unset IFS
	elif [ "$VMVERSION" == "2" ]; then
		if [ "$LISTING" == "long" ]; then
			echo -e "The following $VMNUM VMs are registered \n"
			getallreggedvms
		else
			getallreggedvms > /dev/null
		fi
		## now recreate the array to be able to parse it
		IFS="$(echo -e "\n\r")"
		declare -a NEW_VMARR
		NEW_VMARR=( $(getallreggedvms) )
		# set the variable to 0 before starting the count
		ENABVMNUM=0
		# memorize the original value of IFS for restoring it later
		OLDIFS="$IFS"
		IFS=","
		declare -a THISVMARR
		declare -a ENABVMARR
		for ((idx=0;idx<"$VMNUM";idx++)); do
			THISVMARR=( $(echo "${NEW_VMARR["$idx"]}") )

			DTS=$( echo -e "${THISVMARR[2]}" | tr -d "[]" )
			THISVM="$( echo "$DTS" | sed -e "s:"$DTS":"$GUESTPATH"\/:g" )""$(dirname "${THISVMARR[3]}")"
			if [ -e "$THISVM/.backup" ]; then
				if [ "${#ENABVMARR[*]}" == 0 ]; then
					ENABVM="$THISVM"
				else
					ENABVM="$ENABVM"",""$THISVM"
				fi
				ENABVMARR=( $(echo "$ENABVM") )
			fi
		done
		IFS="$OLDIFS"
		ENABVMNUM="${#ENABVMARR[*]}"
		if [ "$LISTING" == "long" ]; then
			echo -e "\r"
			echo -e "the following ""$ENABVMNUM"" VMs are enabled for backup \n" 	
		fi
		echo -e "${ENABVMARR[*]}"
	fi
	unset IFS
}

##############################
function enablevm {
	VMTOENABLE="$1"
	if [ "$VMTOENABLE" == "" ]; then
		printf "no VM to enable has been supplied\n"
		printf "supply VM name or names separated by commas\n"
		printf "if a VM contains spaces enclose its name in double quotes\n"
		printf "if using VMware Server 2 please specify the datastore too\n"
		printf "using the following format\n"
		printf "backup_vmware -e [standard]/vmname\n"
		printf "if the vmname contains spaces enclose its name in double quotes\n"
		exit 0
	fi

	IFS="\,"

	if [ "$VMVERSION" == "1" ]; then
		a_VMTOENABLE=( $(echo "$VMTOENABLE") )
		for i in "${a_VMTOENABLE[@]}"; do
			if [ -d "$GUESTPATH"/"$i" ]; then
				# add a check to see if the vm is a registered vm (it makes no sense to backup a vm which is not even registered)
				# take the vm name (the vm folder's name) , append the $GUESTCONF to it and then add [standard] in front of it
				# now you can compare its name with the list of registered vms
				# 0 - identify VMware Server version
				# 1 - get the list of vms into a variable
				# 2 - search the list (with grep) and if grep finds the vm, then it's registered
				IFS="$(echo -e "\n\r")"
				VMLIST=$(for i in $(grep -v ^# /etc/vmware/vm-list); do echo -e $i | sed -e 's/config //g' | sed -e 's/"//g'; done)
				IFS="\ "
				if [[ $(echo "$VMLIST" | grep "$GUESTPATH"/"$i") ]]; then
					echo "the VM ""$i"" is registered, enabling it"
					touch "$GUESTPATH"/"$i""/.backup"
				else
					echo "the VM $i is NOT registered, cannot enable it"
				fi	
			fi
		done
	elif [ "$VMVERSION" == "2" ]; then
		a_VMTOENABLE=( $(echo "$VMTOENABLE") )
		for i in "${a_VMTOENABLE[@]}"; do
			# convert the given VM name [datastore]/folder to /fullpath_of_datastore/folder
			# first get the datastore name, then replace it with the full datastore path
			OLDIFS="$IFS"
			IFS="]"
			declare a_i
			a_i=( $(echo "$i" | tr -d "[") )
			IFS="$OLDIFS"
			# ok, now the array a_i contains two elements, the datastore and the VM path
			# now we replace the name of the datastore with its path
			DTSPATH=$( echo "${a_i[0]}" | sed -e "s:"$DATASTORE":"$GUESTPATH":g" )
			if [ -d "$DTSPATH"/"${a_i[1]}" ]; then
				# check if the VM is regged
				if [ $(getvmid_from_datastore_vmpath "$i") ]; then
					echo "the VM ""$i"" is registered, enabling it"
					touch "$DTSPATH"/"${a_i[1]}""/.backup"
				else
					echo "the VM ""$i"" is NOT registered, cannot enable it"
				fi
			else
				echo "VM directory ""$i"" does not exist, cannot enable"
			fi
		done
	fi
	unset IFS
}

##############################
function enableallvm {
	if [ "$VMVERSION" == "1" ]; then
		ENABVM=""
		VMCOUNT=0
		IFS="$(echo -e "\n\r")"
		VMTOENABLE=$(for i in $(grep -v ^# /etc/vmware/vm-list); do echo -e $i | sed -e 's/config //g' | sed -e 's/"//g'; done)
		for l in $(echo -e "$VMTOENABLE"); do
			# check if the VM directory exists [ in fact there may be some registered VMs that don't exist anymore]
			if [ -e "$l" ]; then 
				touch $(dirname "$l")"/.backup"
				VMENABLED="$VMENABLED""\n\r""$l"
				VMCOUNT=`expr $VMCOUNT + 1`;
			fi
		done
		echo -e "the following $VMCOUNT VMs have been enabled for backup"
		echo -e "$VMENABLED"
		unset IFS
	elif [ "$VMVERSION" == "2" ]; then
		ENABVM=""
		declare -a a_ENABVM
		VMCOUNT=0
		#retrieve the list of regged VMs and get it into an array
		IFS="$(echo -e "\n\r")"
		declare -a a_REGGEDVM
		a_REGGEDVM=( $(getallreggedvms) )
		for i in "${a_REGGEDVM[@]}"; do
			# get the datastore name, then replace it with the full datastore path
			OLDIFS="$IFS"
			IFS=","
			declare a_THISVM
			a_THISVM=( $(echo "$i") )
			IFS="$OLDIFS"
			# ok, now the array a_THISVM contains all the needed elements, including the datastore and the VM path
			# now we replace the name of the datastore with its path
			DTSPATH=( $( echo "${a_THISVM[2]}" | tr -d "[]" | sed -e "s:"$DATASTORE":"$GUESTPATH":g" ) )
			VMPATH=$( dirname "$DTSPATH"/"${a_THISVM[3]}")
			if [ -d "$VMPATH" ]; then
				echo "enabling VM $VMPATH"
				touch "$VMPATH""/"".backup"
				if [ "${#a_ENABVM[*]}" == 0 ]; then
					ENABVM="$VMPATH"
				else
					ENABVM="$ENABVM","$VMPATH"
				fi
				OLDIFS="$IFS"
				IFS=","
				a_ENABVM=( $(echo "$ENABVM") )
				IFS="$OLDIFS"
			else
				echo "VM directory ""$DTSPATH"/"${a_THISVM[3]}"" does not exist, cannot enable"
			fi	
		done
		echo -e "\r"
		echo -e "the following ${#a_ENABVM[*]} VMs have been enabled for backup"
		echo -e "${a_ENABVM[*]}"
		unset IFS
	fi
}

##############################
function disablevm {
	VMTODISABLE="$1"
	if [ "$VMTODISABLE" == "" ]; then
		printf "no VM to disable has been supplied\n"
		printf "supply VM name or names separated by commas\n"
		printf "if a VM contains spaces enclose its name in double quotes\n"
		printf "if using VMware Server 2 please specify the datastore too\n"
		printf "using the following format\n"
		printf "backup_vmware -d [standard]/vmname\n"
		printf "if the vmname contains spaces enclose its name in double quotes\n"
		exit 0
	fi

	IFS="\,"

	if [ "$VMVERSION" == "1" ]; then
		a_VMTODISABLE=( $(echo "$VMTODISABLE") )
		for i in "${a_VMTODISABLE[@]}"; do
			if [ -d "$GUESTPATH"/"$i" ]; then
				# add a check to see if the vm is a registered vm (it makes no sense to backup a vm which is not even registered)
				# take the vm name (the vm folder's name) , append the $GUESTCONF to it and then add [standard] in front of it
				# now you can compare its name with the list of registered vms
				# 0 - identify VMware Server version
				# 1 - get the list of vms into a variable
				# 2 - search the list (with grep) and if grep finds the vm, then it's registered
				IFS="$(echo -e "\n\r")"
				VMLIST=$(for i in $(grep -v ^# /etc/vmware/vm-list); do echo -e $i | sed -e 's/config //g' | sed -e 's/"//g'; done)
				IFS="\ "
				if [[ $(echo "$VMLIST" | grep "$GUESTPATH"/"$i") ]]; then
					echo "the VM ""$i"" is registered, disabling it"
					if [ -e "$GUESTPATH"/"$i""/.backup" ]; then
						rm "$GUESTPATH"/"$i""/.backup"
					else
						echo "the VM ""$i"" is not enabled for backup, cannot disable it"
					fi
				else
					echo "the VM $i is NOT registered, cannot disable it"
				fi	
			fi
		done
	elif [ "$VMVERSION" == "2" ]; then
		a_VMTODISABLE=( $(echo "$VMTODISABLE") )
		for i in "${a_VMTODISABLE[@]}"; do
			# convert the given VM name [datastore]/folder to /fullpath_of_datastore/folder
			# first get the datastore name, then replace it with the full datastore path
			OLDIFS="$IFS"
			IFS="]"
			declare a_i
			a_i=( $(echo "$i" | tr -d "[") )
			IFS="$OLDIFS"
			# ok, now the array a_i contains two elements, the datastore and the VM path
			# now we replace the name of the datastore with its path
			DTSPATH=$( echo "${a_i[0]}" | sed -e "s:"$DATASTORE":"$GUESTPATH":g" )
			if [ -d "$DTSPATH"/"${a_i[1]}" ]; then
				# check if the VM is regged
				if [ $(getvmid_from_datastore_vmpath "$i") ]; then
					echo "the VM ""$i"" is registered, disabling it"
					# now check if the .backup file exists , and if it does, then remove it
					if [ -e "$DTSPATH"/"${a_i[1]}""/.backup" ]; then
						rm "$DTSPATH"/"${a_i[1]}""/.backup"
					else
						echo "the VM ""$i"" is not enabled for backup, cannot disable it"
					fi
				else
					echo "the VM ""$i"" is NOT registered, cannot disable it"
				fi
			else
				echo "VM directory ""$i"" does not exist, cannot disable"
			fi	
		done
	fi
	unset IFS
}

##############################
function disableallvm {
	if [ "$VMVERSION" == "1" ]; then
		VMDISABLED=""
		VMCOUNT=0
		IFS="$(echo -e "\n\r")"
		VMTODISABLE=$(for i in $(grep -v ^# /etc/vmware/vm-list); do echo -e $i | sed -e 's/config //g' | sed -e 's/"//g'; done)
		for l in $(echo -e "$VMTODISABLE"); do
			# check if the VM directory exists [ in fact there may be some registered VMs that don't exist anymore]
			if [ -e "$l" ]; then
				# check if the .backup file exists
				VMPATH="$(dirname "$l")"
				if [ -e "$VMPATH"/".backup" ]; then
					echo "Disabling VM $VMPATH"
					rm "$VMPATH"/".backup"
				else
					echo "the VM $VMPATH is not enabled for backup, cannot disable it"
				fi
				VMDISABLED="$VMDISABLED""\n\r""$l"
				VMCOUNT=`expr $VMCOUNT + 1`;
			fi
		done
		echo -e "the following $VMCOUNT VMs have been disabled for backup"
		echo -e "$VMDISABLED"
		unset IFS
	elif [ "$VMVERSION" == "2" ]; then
		DISABVM=""
		declare -a a_DISABVM
		VMCOUNT=0
		#retrieve the list of regged VMs and get it into an array
		IFS="$(echo -e "\n\r")"
		declare -a a_REGGEDVM
		a_REGGEDVM=( $(getallreggedvms) )
		for i in "${a_REGGEDVM[@]}"; do
			# get the datastore name, then replace it with the full datastore path
			OLDIFS="$IFS"
			IFS=","
			declare a_THISVM
			a_THISVM=( $(echo "$i") )
			IFS="$OLDIFS"
			# ok, now the array a_THISVM contains all the needed elements, including the datastore and the VM path
			# now we replace the name of the datastore with its path
			DTSPATH=( $( echo "${a_THISVM[2]}" | tr -d "[]" | sed -e "s:"$DATASTORE":"$GUESTPATH":g" ) )
			VMPATH=$( dirname "$DTSPATH"/"${a_THISVM[3]}")
			if [ -d "$VMPATH" ]; then
				echo "disabling VM $VMPATH"
				rm "$VMPATH""/"".backup"
				if [ "${#a_DISABVM[*]}" == 0 ]; then
					DISABVM="$VMPATH"
				else
					DISABVM="$DISABVM","$VMPATH"
				fi
				OLDIFS="$IFS"
				IFS=","
				a_DISABVM=( $(echo "$DISABVM") )
				IFS="$OLDIFS"
			else
				echo "VM directory ""$DTSPATH"/"${a_THISVM[3]}"" does not exist, cannot disable"
			fi	
		done
		echo -e "\r"
		echo -e "the following ${#a_DISABVM[*]} VMs have been disabled for backup"
		echo -e "${a_DISABVM[*]}"
		unset IFS
	fi
}


##############################
function version {
	printf "backup_vmware.sh version ""$MYVER""\n"
}

##############################
function setslicesize {
	if [ "$1" == "" ]; then
		printf "no slice size has been specified\n"
		printf "but the -S parameter has been explicitly selected\n"
		printf "please supply slice size as a number of megabytes bigger than 100\n"
		printf "or do not specify the -S parameter at all to use the default of 1480m\n"
		exit 0
	elif ( echo "$1" | grep "^[0-9]*$">aux ); then
		if [[ "$1" -ge 100 && "$1" -le 1480 ]]; then
			SLICESIZE="$1"
		else
			printf "invalid value for slicesize option\n"		
			printf "the value for slicesize option\n"
			printf "must be between 100 and 1480\n"
		fi
	else
		printf "unknown value for slicesize option\n"
		printf "supply slicesize as an integer positive number\n"
		printf "included between 100 and 1480\n"
		exit 0
	fi
}

##############################
function setstrategy {
	if [ "$1" == "" ]; then
		printf "no strategy has been specified\n"
		printf "supply strategy as either \"hot\" or \"cold\" \n"
		exit 0
	elif [ "$1" == "hot" -o "$1" == "cold" ]; then
		STRATEGY="$1"
	else
		printf "unknown value for strategy option\n"
		printf "supply strategy as either \"hot\" or \"cold\" \n"
		exit 0
	fi
}

##############################
function setformat {
	## TO DO!
	if [ "$1" == "" ]; then
		printf "no archive format has been specified\n"
		printf "supply format as one of the valid options \n"
		exit 0
	elif [ "$1" == "tar" ]; then
		ARCHIVETYPE="$1"
		ARCHIVESUFFIX="tar"
	elif [ "$1" == "gzip" ]; then
		ARCHIVETYPE="$1"
		ARCHIVESUFFIX="tar.gz"
	elif [ "$1" == "lzop" ]; then
		ARCHIVETYPE="$1"
		ARCHIVESUFFIX="tar.lzo"
	elif [ "$1" == "qpress" ]; then
		ARCHIVETYPE="$1"
	# for quicklz you're supposed to use the very latest version which at the moment of writing is 0.35 BETA - 17-Mar-2009
	# for this version the developer of quicklz suggests to use the qp03 extension , so here it's been updated
		ARCHIVESUFFIX="tar.qp03"
	elif [ "$1" == "copy" ]; then
		ARCHIVETYPE="$1"
		ARCHIVESUFFIX=""
	else
		printf "unknown value for format option \n"
		printf "supply format as one of the valid options \n"
		exit 0
	fi
}

##############################
function clean {
	## TO DO!
	printf "the clean option is not ready yet, please DO NOT USE IT!\n"
	printf "exiting now...\n"
	exit 0
	## when this function will be ready it will set the $CLEANUP variable to "1"
	## and this variable will make the script clean up the VM backup files before recreating them
	## IT IS CURRENTLY DISABLED
	##CLEANUP="1"
}

##############################
function checkpowerstatus {
	## check the VMs power status
	# in case of VMware Server 1.x the output results can be
	# getstate() = on
	# getstate() = off
	# getstate() = suspended
	if [ "$VMVERSION" == "1" ]; then
		PWRSTATUS=$($VMCMD """$1""" getstate )
	elif [ "$VMVERSION" == "2" ]; then
	# in case of VMware Server 2.x the output results (2nd line of it) can be
	# Powered on
	# Powered off
	# Suspended
		# 1 - convert a VM name ( in the format "[datastore]/vm_directory" )  to a VM id
		# 2 - when we've got the id we can simply ask its power status with this command
		# vmware-vim-cmd vmsvc/power.getstate "$ID"
		# TO DO!
		local VMID=$( getvmid_from_datastore_vmpath "$1")
		if [ "$VMID" == "" ]; then
			echo "the specified VM is invalid"
			exit 1
		else
			local CMDOUTPUT=$($VIMCMD -U $VMUSER -P $VMPASS vmsvc/power.getstate "$VMID")
			declare a_PWRSTATUS
			IFS="$(echo -e "\n\r")"
			a_PWRSTATUS=( $(echo "$CMDOUTPUT") )
			PWRSTATUS="${a_PWRSTATUS[1]}"
		fi
		#echo "the VM $1 is ${a_PWRSTATUS[1]}"
		unset IFS
	fi

	# ok, now we got out PWRSTATUS variable, let's clean it out in order to return the same
	# values for whatever the VMware version is
	# the returned values can be: on , off , suspended
	unset a_PWRSTATUS
	declare a_PWRSTATUS
	a_PWRSTATUS=( $(echo "$PWRSTATUS") )
	# get the index of the last element of the array
	local size=${#a_PWRSTATUS[*]}
	local last=$[$size-1]
	PWRSTATUS=$( echo "${a_PWRSTATUS[$last]}" | tr "[:upper:]" "[:lower:]" )
	echo "$PWRSTATUS"
	#exit 0
}

##############################
function suspendvm {
	# this function depends on the vmrun command since it's the only that waits
	# for the completion of the requested operation
	# if someone knows a way to wait for the suspend by using vmware-vim-cmd vmsvc/power.suspend
	# PLEASE TELL ME HOW!
	# TO DO!
	# this function returns error code 47 if there's been an irreversible error (complete failure, 1st suspend + 2nd suspend)
	# it returns error code 48 if there's been some error but it managed to do its job with the fallbacks (2nd suspend)
	local SUSPOK=""
	if [ "$VMVERSION" == "1" ]; then
		# TO DO: add retry after error
		if (("$VMCMD" """$1""" suspend trysoft 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
			SUSPOK="TRUE"
		else
			SUSPOK="FALSE"
		fi
	elif [ "$VMVERSION" == "2" ]; then
		# first we parse the VM name or datastore/name and then we add a space between the datastore name and the VM name
		VM="$1"
		OLDIFS="$IFS"
		IFS="]"
		declare a_VM
		a_VM=( $(echo "$VM" | tr -d "[") )
		IFS="$OLDIFS"
		## echo ${a_VM[0]},${a_VM[1]}
		# now find out the VM id from this data
		local VMID=$( getvmid_from_datastore_vmpath "$1")
		# now find out the .vmx file location from the VM id
		local VMX="$( getvmx_from_vmid $VMID)"
		# perform the actual suspend
		if (("$VMRUN" -h https://127.0.0.1:8333/sdk -u "$VMUSER" -p "$VMPASS" suspend "$VMX" 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
			SUSPOK="TRUE"
		else
			SUSPOK="FALSE"
		fi
	fi
	# error checking
	# all went ok, error code 0
	if [ "$SUSPOK" == "TRUE" ]; then
		echo "SUSPOK = $SUSPOK"
		return 0
	# the start failed , error code 47
	else
		echo "SUSPOK = $SUSPOK"
		return 47
	fi
}

##############################
function snapshotvm {
	# this function depends on the vmrun command since it's the only that waits
	# for the completion of the requested operation
	# if someone knows a way to wait for the snapshot by using vmware-vim-cmd vmsvc/snapshot.create
	# PLEASE TELL ME HOW!
	# TO DO!
	# this function returns error code 49 if there's been an irreversible error (complete failure, 1st snapshot + 2nd snapshot + suspend)
	# it returns error code 50 if there's been some error but it managed to do its job with the fallbacks (2nd snapshot or suspend)
	# the SNAPOK variable is TRUE only if the snapshot succeeds (the first or the second attempt, it doesn't matter)
	# if the snapshot fails a suspension is tried and if it succeeds the FALLBACKSUSPOK variable is set to TRUE
	# if even the suspension fails then the snapshot is declared to be failed and also the FALLBACKSUSPOK is set to FALSE
	local SNAPOK=""
	local FALLBACKSUSPOK=""
	if [ "$VMVERSION" == "1" ]; then
		if (("$VMRUN" snapshot """$1""" 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
		# comment the line above and uncomment the line below to simulate a failure of the first snapshot attempt
		##if false; then
			SNAPOK="TRUE"
			## BEGIN - DIAGNOSTIC MESSAGES
			MSG="$(now)$MSG70"
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi	
			echo "$MSG" >> "$TEMPLOG"			
			## END - DIAGNOSTIC MESSAGES			
		else
			# if there's an error then retry the snapshot
			SNAPOK="FALSE"
			echo "SNAPOK = $SNAPOK"
			## BEGIN - DIAGNOSTIC MESSAGES			
			MSG="$(now)$MSG71"
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi	
			echo "$MSG" >> "$TEMPLOG"	
			## END - DIAGNOSTIC MESSAGES				
			# wait 5 seconds just to give the VM time to complete eventual "state change" operations
			sleep 5
			if (("$VMRUN" snapshot """$1""" 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
			# comment the line above and uncomment the line below to simulate a failure of the second snapshot attempt
			##if false; then
				SNAPOK="TRUE"
				## BEGIN - DIAGNOSTIC MESSAGES
				MSG="$(now)$MSG72"		
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi	
				echo "$MSG" >> "$TEMPLOG"		
				## END - DIAGNOSTIC MESSAGES					
			else
				## BEGIN - DIAGNOSTIC MESSAGES
				MSG="$(now)$MSG73"		
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi	
				echo "$MSG" >> "$TEMPLOG"		
				## END - DIAGNOSTIC MESSAGES
			# if it still doesn't work, fallback to suspending the VM, but only if the --nosuspend option hasn't been enabled
				if [ "$NOSUSPEND" == "TRUE" ]; then
					SNAPOK="FALSE"
					FALLBACKSUSPOK="FALSE"				
					MSG="$(now)$MSG76"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi	
					echo "$MSG" >> "$TEMPLOG"	
				else
					# wait 5 seconds just to give the VM time to complete eventual "state change" operations
					sleep 5		
					if ( suspendvm """$1""" ) ; then
					# comment the line above and uncomment the line below to simulate a failure of the second snapshot attempt
					##if false; then
						SNAPOK="FALSE"
						# if the suspend went ok then log the fact
						FALLBACKSUSPOK="TRUE"
						## BEGIN - DIAGNOSTIC MESSAGES
						MSG="$(now)$MSG74"		
						if [ "$DEBUG" ]; then
							echo "$MSG"
						fi	
						echo "$MSG" >> "$TEMPLOG"		
						## END - DIAGNOSTIC MESSAGES						
					# if the suspend failed too, then log it
					else
						SNAPOK="FALSE"
						FALLBACKSUSPOK="FALSE"
						## BEGIN - DIAGNOSTIC MESSAGES
						MSG="$(now)$MSG75"
						if [ "$DEBUG" ]; then
							echo "$MSG"
						fi	
						echo "$MSG" >> "$TEMPLOG"		
						## END - DIAGNOSTIC MESSAGES
					fi
				fi
			fi
		fi
	elif [ "$VMVERSION" == "2" ]; then
		# first we parse the VM name or datastore/name and then we add a space between the datastore name and the VM name
		VM="$1"
		OLDIFS="$IFS"
		IFS="]"
		declare a_VM
		a_VM=( $(echo "$VM" | tr -d "[") )
		IFS="$OLDIFS"
		## echo ${a_VM[0]},${a_VM[1]}
		# now find out the VM id from this data
		local VMID=$( getvmid_from_datastore_vmpath "$1")
		# now find out the .vmx file location from the VM id
		local VMX="$( getvmx_from_vmid $VMID)"
		# perform the actual snapshot
		if (("$VMRUN" -h https://127.0.0.1:8333/sdk -u "$VMUSER" -p "$VMPASS" snapshot "$VMX" 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
		# comment the line above and uncomment the line below to simulate a failure of the first snapshot attempt
		##if false; then
			SNAPOK="TRUE"
			## BEGIN - DIAGNOSTIC MESSAGES
			MSG="$(now)$MSG70"
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi	
			echo "$MSG" >> "$TEMPLOG"			
			## END - DIAGNOSTIC MESSAGES				
			else
			# if there's an error then retry the snapshot
			SNAPOK="FALSE"
			## BEGIN - DIAGNOSTIC MESSAGES			
			MSG="$(now)$MSG71"
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi	
			echo "$MSG" >> "$TEMPLOG"	
			## END - DIAGNOSTIC MESSAGES			
			# wait 5 seconds just to give the VM time to complete eventual "state change" operations
			sleep 5		
			if (("$VMRUN" -h https://127.0.0.1:8333/sdk -u "$VMUSER" -p "$VMPASS" snapshot "$VMX" 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
			# comment the line above and uncomment the line below to simulate a failure of the second snapshot attempt
			##if false; then
			SNAPOK="TRUE"
			## BEGIN - DIAGNOSTIC MESSAGES
			MSG="$(now)$MSG72"		
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi	
			echo "$MSG" >> "$TEMPLOG"		
			## END - DIAGNOSTIC MESSAGES				
			else
			## BEGIN - DIAGNOSTIC MESSAGES
			MSG="$(now)$MSG73"		
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi	
			echo "$MSG" >> "$TEMPLOG"		
			## END - DIAGNOSTIC MESSAGES			
			# if it still doesn't work, fallback to suspending the VM, but only if the --nosuspend option hasn't been enabled
				if [ "$NOSUSPEND" == "TRUE" ]; then
					SNAPOK="FALSE"
					FALLBACKSUSPOK="FALSE"				
					MSG="$(now)$MSG76"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi	
					echo "$MSG" >> "$TEMPLOG"	
				else
				# wait 5 seconds just to give the VM time to complete eventual "state change" operations
					sleep 5
					if ( suspendvm """$1""" ) ; then
					# comment the line above and uncomment the line below to simulate a failure of the suspension attempt
					##if false; then	
						SNAPOK="FALSE"
						# if the suspend went ok then log the fact
						FALLBACKSUSPOK="TRUE"
						## BEGIN - DIAGNOSTIC MESSAGES
						MSG="$(now)$MSG74"		
						if [ "$DEBUG" ]; then
							echo "$MSG"
						fi	
						echo "$MSG" >> "$TEMPLOG"		
						## END - DIAGNOSTIC MESSAGES							
					# if the suspend failed too, then log it
					else
						SNAPOK="FALSE"
						FALLBACKSUSPOK="FALSE"
						## BEGIN - DIAGNOSTIC MESSAGES
						MSG="$(now)$MSG75"
						if [ "$DEBUG" ]; then
							echo "$MSG"
						fi	
						echo "$MSG" >> "$TEMPLOG"		
						## END - DIAGNOSTIC MESSAGES						
					fi
				fi
			fi
		fi
	fi
	# error checking
	# all went ok, error code 0
	if [ "$SNAPOK" == "TRUE" ]; then
		echo "SNAPOK = $SNAPOK"
		return 0
	# the snapshot failed but the suspension worked, error code 0
	elif [ "$SNAPOK" == "FALSE" ] && [ "$FALLBACKSUSPOK" == "TRUE" ]; then
		echo "SNAPOK = $SNAPOK"
		echo "FALLBACKSUSPOK = $FALLBACKSUSPOK"
		return 0
	# both the snapshot and suspension failed, error code 49
	else #[ "$SNAPOK" == "FALSE" ] && [ "$FALLBACKSUSPOK" == "FALSE" ]; then
		echo "SNAPOK = $SNAPOK"
		echo "FALLBACKSUSPOK = $FALLBACKSUSPOK"
		return 49
	fi
}

##############################
function startvm {
	# this function is used to start a VM (for example after it was suspended)
	# it relies on the vmrun command since it's the only that waits for the completion of the requested operation
	# if someone knows a way to wait for the restart by using vmware-vim-cmd vmsvc/power.on
	# PLEASE TELL ME HOW!
	# this function returns error code 51 if there's been an irreversible error
	# the STARTOK variable will be set to TRUE if the VM started successfully, otherwise it will be set to FALSE
	local STARTOK=""
	if [ "$VMVERSION" == "1" ]; then
		# TO DO: add retry after error
		if (( "$VMCMD" """$1""" start trysoft 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then	
			STARTOK="TRUE"
		else
			STARTOK="FALSE"
		fi		
	elif [ "$VMVERSION" == "2" ]; then
		# first we parse the VM name or datastore/name and then we add a space between the datastore name and the VM name
		VM="$1"
		OLDIFS="$IFS"
		IFS="]"
		declare a_VM
		a_VM=( $(echo "$VM" | tr -d "[") )
		IFS="$OLDIFS"
		#echo ${a_VM[0]},${a_VM[1]}
		# now find out the VM id from this data
		local VMID=$( getvmid_from_datastore_vmpath "$1")
		# now find out the .vmx file location from the VM id
		local VMX="$( getvmx_from_vmid $VMID)"
		# perform the actual suspend
		if (( "$VMRUN" -h https://127.0.0.1:8333/sdk -u "$VMUSER" -p "$VMPASS" start "$VMX" 2>&1 1>&3 | tee -a /tmp/errors.log) 3>&1 1>&2 | tee -a /tmp/output.log) >> /tmp/final.log 2>&1 ; then
			STARTOK="TRUE"
		else
			STARTOK="FALSE"
		fi
	fi
	# error checking
	# all went ok, error code 0
	if [ "$STARTOK" == "TRUE" ]; then
		echo "STARTOK = $STARTOK"
		return 0
		# the start failed , error code 51
	else
		echo "STARTOK = $STARTOK"
		return 51
	fi
}

##############################
function backupvm {
	if [ "$DEBUG" ]; then
		echo "MYFUNCTION - backupvm MYFUNCTION"
		echo "variable list"
		echo "\$STRATEGY = $STRATEGY"
		echo "\$DEBUG = $DEBUG"
		echo "\$ARCHIVETYPE = $ARCHIVETYPE"
		echo "\$GUESTPATH = $GUESTPATH"
		echo "\$LVM = $LVM"
		echo "\$SNAPPATH = $SNAPPATH"
		echo "\$GUESTNAME = $GUESTNAME"
		echo "\$TEMPLOG = $TEMPLOG"
		echo "\$SLICESIZE = $SLICESIZE"
		echo "\$BACKPATH = $BACKPATH"
		echo "\$ARCHIVESUFFIX = $ARCHIVESUFFIX"
	fi

	# if LVM snapshot are in use then set a local copy of $GUESTPATH to the value of $SNAPPATH in order to read from that path the files to backup
	if [ "$LVM" == "true" ]; then
		local GUESTPATH="$SNAPPATH"
	fi

	MSG="$(now)$MSG59"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi
	echo "$MSG" >> "$TEMPLOG"
	## set the string which will contain the commands to archive the VM
	if [ "$ARCHIVETYPE" == "tar" ]; then
		ARCHIVECMD="tar --ignore-failed-read -C \"""$GUESTPATH""\" -cf - \"""$GUESTNAME/""\" 2>>""$TEMPLOG"" | split -b $SLICESIZE - \"""$BACKPATH""/""$GUESTNAME"".""$ARCHIVESUFFIX""\" 2>>""$TEMPLOG"""
	elif [ "$ARCHIVETYPE" == "gzip" ]; then
		ARCHIVECMD="tar --ignore-failed-read -C \"""$GUESTPATH""\" -zcf - \"""$GUESTNAME/""\" 2>>""$TEMPLOG"" | split -b $SLICESIZE - \"""$BACKPATH""/""$GUESTNAME"".""$ARCHIVESUFFIX""\" 2>>""$TEMPLOG"""
	elif [ "$ARCHIVETYPE" == "lzop" ]; then
		ARCHIVECMD="tar --ignore-failed-read --use-compress-program=lzop -C \"""$GUESTPATH""\" -cf - ""\"$GUESTNAME/\""" 2>>""$TEMPLOG"" | split -b $SLICESIZE - \"""$BACKPATH""/""$GUESTNAME"".""$ARCHIVESUFFIX""\" 2>>""$TEMPLOG"""
	elif [ "$ARCHIVETYPE" == "qpress" ]; then
		ARCHIVECMD="tar --ignore-failed-read -C \"""$GUESTPATH""\" -cf - \"""$GUESTNAME/""\" 2>>""$TEMPLOG"" | qpress -fc ""$GUESTNAME/"" |split -b $SLICESIZE - \"""$BACKPATH""/""$GUESTNAME"".""$ARCHIVESUFFIX""\" 2>>""$TEMPLOG"""
	elif [ "$ARCHIVETYPE" == "copy" ]; then
		ARCHIVECMD="cp -r \"""$GUESTPATH""/""$GUESTNAME/""\" \"""$BACKPATH/""\" 2>>""$TEMPLOG"""		
	fi		
	## store the VM in a tar archive splitting it in slices of predefined size ($SLICESIZE) each
	if eval "$ARCHIVECMD" ; then
		if [ "$ARCHIVETYPE" == "copy" ]; then
			MSG="$(now)$MSG61A$GUESTNAME$MSG61B"
		else
			MSG="$(now)$MSG32A$GUESTNAME.$ARCHIVESUFFIX$MSG32B"
		fi
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi
		echo "$MSG" >> "$TEMPLOG"
	else
		if [ "$ARCHIVETYPE" == "copy" ]; then
			MSG="$(now)$MSG62$GUESTNAME$"
		else
			MSG="$(now)$MSG33A$GUESTNAME.$ARCHIVESUFFIX$MSG33B"
		fi
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi		
		echo "$MSG" >> "$TEMPLOG"
		# if there have been errors in this phase they could simply be "tar errors" (for example: tar: "myfile": file changed as we read it)
		# but the backup is still valid so it's better to go on to the next step which could also be the resume of the VM if it was suspended
		GUESTERROR="$GUESTERROR""\""$GUESTNAME"\" "		
		THISGUESTOK="FALSE"
	fi
}

##############################
function usage {
	cat << EOF
Usage: backup_vmware.sh parameters

-s, --strategy	[opt]	Set the backup strategy
			[hot] back up the VM by snapshotting them
			[cold] back up the VMs by suspending them
-ns --nosuspend 	Disable the fallback to suspension in case 
			the snapshot creation fails
			This is to avoid long periods of downtime
			in case the snapshot creation fails on a vm			
-f, --format	[opt]	Set the archiver type
			[tar] store the VMs in a tar archive
			[gzip] store the VMs in a tar.gz archive
			[lzop] store the VMs in a tar.lzop archive
			[qpress] store the VMs in a tar.qp01 archive
			[copy] simply copy the VMs folders to the storage
-S --slicesize [opt]	Set the desired slice size in megabytes
			by default the slice size will be 1480m, so that
			three slices will fill a normal DVD disc
			please note it must be at least 100m or more
-D, --debug		Run the script with debug mode
-c, --check		Check all parameters
-l, --listvm [opt]	List virtual machines enabled for backup
			[long] list the full paths to the .vmx files
			[short] list only the VM folder names
-L, --lang [opt]	Set script language
			[en] set the script to english language
			[it] set the script to italian language
-e, --enablevm VM	Enable one or more VMs to be backed up
			separate multiple VMs with commas
			enclose in double quotes if containing spaces
-ea, --enableallvm 	Enable all (registered) VMs to be backed up
-d, --disablevm VM	Disable one or more VMs to be backed up
			separate multiple VMs with commas
			VMs with spaces must be enclosed in double quotes
-da, --disableallvm 	Disable all VMs to be backed up
-V, --version		Output version information
-?, --usage		Output this usage information
EOF
  }
  
  if [ "$#" == "0" ]; then
	echo "please supply an argument"
	exit 1
else
	while [ "$#" -gt "0" ]
	do
	    case $1 in
			-l|--listvm)
				shift
				listvm "$1"
				exit 0
				;;
			-e|--enablevm)
				shift
				enablevm "$1"
				exit 0
				;;
			-ea|--enableallvm)
				shift
				enableallvm
				exit 0
				;;
			-d|--disablevm)
				shift
				disablevm "$1"
				exit 0
				;;
			-da|--disableallvm)
				shift
				disableallvm
				exit 0
	            ;;
########## BEGIN TEST FUNCTIONS ###########		
			# remove this!
			# test for the now() function
			-now)
				now
				exit 0
				;;	
			# remove this!
			# test for the trim) function
			-trim)
				shift
				trim "$1"
				exit 0
				;;	
			# remove this!
			# return the vm id from the vm definition (es: [standard]/directory_of_the_vm )
			-getallvms_to_vminfo)
				shift
				getallvms_to_vminfo "$1"
				exit 0
				;;
			# remove this!
			# return the vm data for all regged vms
			-getallreggedvms)
				shift
				getallreggedvms
				exit 0
				;;
			# remove this!
			# return the vm id from the vm definition (es: [standard]/directory_of_the_vm )
			-getvmid_from_datastore_vmpath)
				shift
				getvmid_from_datastore_vmpath "$1"
				exit 0
				;;
			# remove this!
			# return the ["datastore] /vm_folder/vmxfile.vmx"  from the vm id 
			-getvmx_from_vmid)
				shift
				getvmx_from_vmid "$1"
				exit 0
				;;
			# remove this!
			# return the list of all registered vms and the list of those currently enabled for backup
			-listvm)
				listvm
				exit 0
				;;
			# remove this!
			# return the current power status of a given vm
			-checkpowerstatus)
				shift
				checkpowerstatus "$1"
				exit 0
				;;
			# remove this!
			# suspend a given vm
			-suspendvm)
				shift
				suspendvm "$1"
				exit 0
				;;
			# remove this!
			# snapshot a given vm
			-snapshotvm)
				shift
				snapshotvm "$1"
				exit 0
				;;
			# remove this!
			# start (or resume) a given vm
			-startvm)
				shift
				startvm "$1"
				exit 0
				;;
########## END TEST FUNCTIONS ###########
			-D|--debug)
				DEBUG="1"
				;;
			-s|--strategy)
				shift
				setstrategy "$1"
				;;
			-ns|--nosuspend)
				NOSUSPEND="TRUE"
				;;				
			-f|--format)
				shift
				setformat "$1"
				;;
			-S|--slicesize)
				shift
				setslicesize "$1"
				;;	
			-L|--lang)
				shift
				setmylang "$1"
				;;
			# remove this!
			-vmx)
				shift
				getvmx_from_vmid "$1"
				exit 0
				;;				
			-c|--check)
				CHECKMODE="1"
				DEBUG="1"		
				;;
			-C|--clean)
				clean
				;;
			-\?|--usage)
				usage
				exit 0
				;;
			-V|--version)
				version
				exit 0
				;;
			*)
				echo "Syntax Error"
				usage
				exit 1
				;;
		esac
		shift
	done
fi

##############################
# LOAD ERROR MESSAGE TRANSLATIONS
# NOTE: if the file doesn't exist , stop the script
##############################
if [ -e "$CURRENTPATH"/backup_vmware.conf ]; then
	source "$CURRENTPATH"/backup_vmware.conf
else
	echo "The translation file is not present, cannot continue "
	echo "please ensure that the \"backup_vmware.conf\" file is " 
	echo "present in the same directory of this script "
	exit 1
fi

if [ "$DEBUG" == "1" ]; then
    echo "$MSG0"
else
    echo "$MSG1"
fi

if [ "$CHECKMODE" == "1" ]; then
    echo "$MSG57"
fi

##############################
# SCRIPT STARTUP
##############################
MSG="$(now)$MSG2"
if [ "$DEBUG" ]; then
	echo "$MSG"
fi
echo "$MSG" > "$TEMPLOG"

##############################
# CHECK PATHS
##############################
## 1 - checks the paths defined in the variables
## set the $CHECKDIR variable to "OK"
## if at the end of the checks it's still "OK" then the checks are all passed
## also checks if the VMVERSION has been correctly determined
if [ -d "$GUESTPATH" ] ; then
	true
else
	CHECKDIR="ERRORE"
	MSG="$(now)$MSG3"'($GUESTPATH)'
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi
	echo "$MSG" >> "$TEMPLOG"
fi
## check existence and mount status of $BACKPATH
if [ -d "$BACKPATH" ] ; then
	true
#	if mount | grep $BACKPATH > /dev/null ; then
#		true
#	else
#		CHECKDIR="ERRORE"
#		MSG="$(now)$MSG4"'($BACKPATH)'
#		if [ $DEBUG ]; then
#			echo "$MSG"
#		fi		
#		echo "$MSG" >> $TEMPLOG
#	fi
else
	CHECKDIR="ERRORE"
	MSG="$(now)$MSG5"'($BACKPATH)'
	## if the $BACKLOG doesn't exist nothing can be logged to it so it's better to echo the error message in console and exit directly
	echo "$MSG"
	exit 1
fi
## check existence of $SNAPPATH (only if LVM snapshots are chosen)
if [ "$LVM" == "true" ] ; then
	if [ -d "$SNAPPATH" ] ; then
		true
	else
		CHECKDIR="ERRORE"
		DATE=$(date "+%Y-%m-%d [%k:%M:%S]")
		MSG="$(now)$MSG6"'($SNAPPATH)'
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi		
		echo "$MSG" >> "$TEMPLOG"
	fi
fi
## if one or more of these checks failed, then stop the script
if [ "$CHECKDIR" == "ERRORE" ] ; then
	MSG="$(now)$MSG8"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi		
	echo "$MSG" >> "$TEMPLOG"
	cat "$TEMPLOG" >> "$LOG"
	exit 1
else if [ "$VMVERSION" == "ERROR" ]; then
	MSG="$(now)$MSG64"'($VMVERSION)'
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi
	echo "$MSG" >> "$TEMPLOG"
	cat "$TEMPLOG" >> "$LOG"
	exit 1
	fi
	# there aren't errors so log it and go on
	MSG="$(now)$MSG9"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
fi

## NON FATAL ERRORS
## check if the sendEmail command really exists
if [ ! -e "$SENDEMAIL" ]; then
	MSG="$(now)$MSG55"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
fi

##############################
# SANITY CHECKS
##############################
## prevent running the script if vmware server "background snapshots" are enabled
## if the two lines in the /etc/vmware/config file are not present or don't contain "FALSE" as a value
## then assume the "background snapshots" are enabled and exit the script immediately
## prevent running the script if the $LVM or $STRATEGY or $ARCHIVETYPE or $SLICESIZE are not set or incorrectly set
## or if any other sanity check fails (eg: the check for background snapshots)
# sets the $SANITY value to 0, if at the end of the controls it's > 0 there's been one or more errors so exit
SANITY=0
if !( $(grep -q "^mainMem.partialLazySave = \"FALSE\"" /etc/vmware/config) ) ||
	!( $(grep -q "^mainMem.partialLazyRestore = \"FALSE\"" /etc/vmware/config) ); then
	MSG="$(now)$MSG48"
	echo -e "$MSG"
	echo -e "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))	
fi
if !([ "$LVM" == "true" ] || [ "$LVM" == "false" ]) ; then
	MSG="$(now)$MSG49"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))
fi
if !([ "$STRATEGY" == "hot" ] || [ "$STRATEGY" == "cold" ]) ; then
	MSG="$(now)$MSG50"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))
fi
if !([ "$ARCHIVETYPE" == "tar" ] || [ "$ARCHIVETYPE" == "gzip" ] || [ "$ARCHIVETYPE" == "lzop" ] || [ "$ARCHIVETYPE" == "qpress" ] || [ "$ARCHIVETYPE" == "copy" ]) ; then
	MSG="$(now)$MSG51"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))
fi
if !(( echo "$SLICESIZE" | grep "^[0-9]*$">aux ) && [ "$SLICESIZE" -gt 100 ]); then
	MSG="$(now)$MSG63"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))
else
	# add the "m" to the $SLICESIZE variable to make it compatible with the split command
	SLICESIZE="$SLICESIZE""m"
fi
if [ "$LVCREATE" == "error" ]; then
	MSG="$(now)$MSG65"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))
fi
if [ "$LVREMOVE" == "error" ]; then
	MSG="$(now)$MSG66"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	SANITY=$(($SANITY + 1))
fi	
## finally, if the $SANITY variable is bigger than 0, there's been an error, so stop the execution and log the error
if [ "$SANITY" -gt 0 ] ; then
	MSG="$(now)$MSG52"
	echo "$MSG"
	echo "$MSG" >> "$TEMPLOG"
	exit 1
else
	MSG="$(now)$MSG53"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
fi

##############################
# CREATION OF THE LIST OF VMs TO BE BACKED UP
##############################
# 2 - $GUESTPATH folder is scanned to find which folders contain the ".backup" file
# 	if a folder does indeed contain the ".backup" file it means it has to be backed up, else it will be discarded
# the $VM_LIST variable will contain the list, one line at a time, of the names of the folders to be backed up
VM_LIST=""
if [ "$VMVERSION" == "1" ]; then
	VM_LIST="$( listvm short | sed -e 's/.*\///')"
elif [ "$VMVERSION" == "2" ]; then
	# for now let's assume the datastore is only the [standard] one
	# but in the future it will be necessary to search every datastore
	# or maybe we can add a command line parameter to run the script on a  specific datastore
	# not the most practical but it can work (you run the script for each datastore containing VMs to be backed up)
	VM_LIST="$( listvm short | sed -e 's/.*\///')"
fi

declare -a a_VM_LIST
IFS="$(echo -e "\n\r")"
a_VM_LIST=( $(echo "$VM_LIST") )
numvm=${#a_VM_LIST[*]}
unset IFS

if [ ${#a_VM_LIST[*]} == 0 ]; then
	MSG="$(now)$MSG56"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
	exit 1
else
	MSG="$(now)$MSG54"
	if [ "$DEBUG" ]; then
		echo -e "$MSG""$VM_LIST"
	fi	
	echo -e "$MSG""$VM_LIST" >> "$TEMPLOG"
fi

if [ "$CHECKMODE" == "1" ]; then
	MSG="$(now)$MSG58"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
	exit 0
fi

##############################
# START MAIN LOOP
##############################
# This loop parses all the folders to be backed up and then backs them up
for (( i = 0 ; i < ${#a_VM_LIST[*]} ; i++ )); do
	THISGUESTOK=""
	RESTART=""
	SUSPEND=""
	GUESTNAME="${a_VM_LIST[$i]}"
	if [ "$VMVERSION" == "1" ]; then
		GUESTCONF=$(ls "$GUESTPATH"/"$GUESTNAME"/*.vmx)
	elif [ "$VMVERSION" == "2" ]; then
		# let's convert the GUESTCONF variable to the format "[datastore]/vmpath/vmxfile.vmx"
		GUESTCONF="[$DATASTORE]"/"$GUESTNAME"
	fi
	# is the GUESTVMX variable ever used??
	# well, for VMware Server 2 it's not needed so let's define it only for VMware Server 1
	if [ "$VMVERSION" == "1" ]; then
		GUESTVMX="$(echo $GUESTCONF | sed -e 's/.*\///')"
	fi	
	echo "\$GUESTCONF = $GUESTCONF"
	echo "\$GUESTVMX = $GUESTVMX"
	MSG="$(now)$MSG10A$GUESTNAME$MSG10B"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi		
	echo "$MSG" >> "$TEMPLOG"
	# reset the $THISGUESTOK variable since it could have been left dirty from the previous iteration
	THISGUESTOK=""

	##############################
	# ANALYSIS OF THE VM STATUS: 
	# IF IT'S STARTED DOES THE SNAPSHOT OR SUSPEND
	# ELSE IT WILL DIRECTLY COPY THE FILES
	##############################
	## check if the VM is started
	PWRSTATUS=$( checkpowerstatus """$GUESTCONF""" )
	checkpowerstatus """$GUESTCONF"""
	## sleep 5 seconds just to leave it the time to finish writing the vmware logfile to avoid tar giving out "file changed as we read it" error
	sleep 5
	if [ "$PWRSTATUS" == "on" ]; then
		RESTART="YES"
		MSG="$(now)$MSG11A$GUESTNAME$MSG11B"
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi		
		echo "$MSG" >> "$TEMPLOG"
		## the script choses the backup strategy depending on the $STRATEGY value
		if [ "$STRATEGY" == "hot" ] ; then
			# the triple quotes are necessary or vmrun will fail in case of paths with spaces
			# this line does redirect the stdout and stderr of the vmrun command in three files in the $TMP folder
			if ( snapshotvm """$GUESTCONF""" ) ; then
				SNAPSHOT="OK"
				MSG="$(now)$MSG12A$GUESTNAME$MSG12B"
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi
				echo "$MSG" >> "$TEMPLOG"
				sleep 2
			# TO DO: convert to elif and add the check for the fallback 2nd snapshot or suspend
			else
				SNAPSHOT="ERRORE"
				MSG="$(now)$MSG15$GUESTNAME"
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi
				echo "$MSG" >> "$TEMPLOG"
				# if there have been errors in the snapshot they must be logged
				GUESTERROR="$GUESTERROR""\"""$GUESTNAME"\"" "
				THISGUESTOK="FALSE"
			fi
		elif [ "$STRATEGY" == "cold" ] ; then	
			if ( suspendvm """$GUESTCONF""" ) ; then
				SUSPEND="OK"
				sleep 1
				MSG="$(now)$MSG13A$GUESTNAME$MSG13B"
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi				
				echo "$MSG" >> "$TEMPLOG"
				else
				SUSPEND="ERRORE"
				MSG="$(now)$MSG14$GUESTNAME"
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi					
				echo "$MSG" >> "$TEMPLOG"
				# if there have been errors in the suspend they must be logged
				GUESTERROR="$GUESTERROR""\"""$GUESTNAME"\"" "
				THISGUESTOK="FALSE"
			fi
		fi
	elif [ "$PWRSTATUS" == "suspended" ]; then
		# if the VM is already suspended, then there's no need to suspend it or to make the LVM snapshot
		# so it skips these parts and proceeds with the archive creation
		RESTART="NO"
		MSG="$(now)$MSG16A$GUESTNAME$MSG16B"
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi
		echo "$MSG" >> "$TEMPLOG"
	elif [ "$PWRSTATUS" == "off" ]; then
		# if the VM is powered off , then there's no need to suspend it or to make the LVM snapshot
		# so it skips these parts and proceeds with the archive creation
		RESTART="NO"
		MSG="$(now)$MSG17A$GUESTNAME$MSG17B"
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi
		echo "$MSG" >> "$TEMPLOG"
	fi

	## now the VM is snapshotted/suspended
	if [ "$RESTART" = "YES" ] ; then
		## Now that the snapshot/suspend is completed we need to check if LVM snapshots are enabled and if the VM was powered on
		## in fact if it was not powered on it would be useless to make a LVM snapshot of it since it's already frozen
		if [ "$LVM" == "true" ] ; then
		## if the snapshot/suspend is ok then create the LVM snapshot
			if  [ "$SNAPSHOT" == "OK" ] || [ "$SUSPEND" == "OK" ]; then
				# just to be safe, umount the $SNAPPATH (it may be mounted for whatever reason)
				"$UMOUNT" -f "$SNAPPATH"
				MSG="$(now)$MSG18"
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi
				echo "$MSG" >> "$TEMPLOG"
				# creates the LVM snapshot
				if "$LVCREATE" -l"$LVSNAPSIZE" -s -n "$LVSNAP" "$VG""/""$LV" ; then
					MSG="$(now)$MSG19"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi
					echo "$MSG" >> "$TEMPLOG"
				else
					MSG="$(now)$MSG20"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi
					echo "$MSG" >> "$TEMPLOG"
					continue
				fi
				# mount the LVM snapshot in $SNAPPATH to make it accessible
				sleep 1
				if "$MOUNT" -o ro "$VG""/""$LVSNAP" "$SNAPPATH" ; then
					MSG="$(now)$MSG21"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi
					echo "$MSG" >> "$TEMPLOG"
				else
					MSG="$(now)$MSG22"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi
					echo "$MSG" >> "$TEMPLOG"
					continue
				fi
			fi
			## now that the LVM snapshot is mounted we are ready to archive the VM
			## but first, if the VM has been suspended it must be resumed
			## if the VM needs restarting then restart it, else do nothing and only log it
			if [ "$STRATEGY" == "cold" ] ; then
				sleep 1
				if ( startvm """$GUESTCONF""" ) ; then
					RESTARTSTATUS="OK"
					MSG="$(now)$MSG25"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi					
					echo "$MSG" >> "$TEMPLOG"
				else
					RESTARTSTATUS="ERRORE"
					MSG="$(now)$MSG26$GUESTNAME"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi						
					echo "$MSG" >> "$TEMPLOG"
					# if there's been some error then log it and go on
					GUESTERROR="$GUESTERROR""\"""$GUESTNAME"\"" "
					THISGUESTOK="FALSE"
				fi
			fi
			## LVM=YES
			## ok, now the VM , whether it was an hot or cold backup, can be archived
			## echo to log (and to output if debug mode is enabled) that the archiving operation is starting
			backupvm "$GUESTNAME"
			## now that the VM has been archived , umount the LVM snapshot and remove it
			"$UMOUNT" -f "$SNAPPATH"
			MSG="$(now)$MSG30"
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi					
			echo "$MSG" >> "$TEMPLOG"
			"$LVREMOVE" -f "$VG""/""$LVSNAP"
			MSG="$(now)$MSG31"
			if [ "$DEBUG" ]; then
				echo "$MSG"
			fi					
			echo "$MSG" >> "$TEMPLOG"
		
			# this VM doesn't need to be restarted (wasn't powered on in the first place), then don't do it and log the fact
			if [ "$RESTART" = "NO" ]; then
				MSG="$(now)$MSG27"
				if [ "$DEBUG" ]; then
					echo "$MSG"
				fi					
				echo "$MSG" >> "$TEMPLOG"
			fi
	
		## if the LVM option is disabled then proceed consequently
		elif [ "$LVM" == "false" ] ; then
			## LVM=NO , STRATEGY=hot			
			## now that the VM (whether snapshotted or suspended) is in a consistent state it can be archived
			## echo to log (and to output if debug mode is enabled) that the archiving operation is starting
			backupvm "$GUESTNAME"
#			## ok, now the VM is archived, if it needs restarting then do it
			if [ "$STRATEGY" == "cold" ] ; then
				sleep 1
				if ( startvm """$GUESTCONF""" ) ; then
					RESTARTSTATUS="OK"
					MSG="$(now)$MSG25"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi					
					echo "$MSG" >> "$TEMPLOG"
				else
					RESTARTSTATUS="ERRORE"
					MSG="$(now)$MSG26$GUESTNAME"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi						
					echo "$MSG" >> "$TEMPLOG"
					# if there's been some error then log it and go on
					GUESTERROR="$GUESTERROR""\"""$GUESTNAME"\"" "
					THISGUESTOK="FALSE"
				fi
## now , even if the strategy was "hot", the snapshot may have failed and so the VM did fall back to the suspend mode
			## so the VM is now suspended, and then it must be restarted
			## BUT first the powerstatus of the VM must be checked again, or else we risk to try to start a VM which is already started
			elif [ "$STRATEGY" == "hot" ] && [ "$RESTART" == "YES" ] && [ "$( checkpowerstatus """$GUESTCONF""" )" == "suspended" ]; then
				sleep 1
				if ( startvm """$GUESTCONF""" ) ; then
					RESTARTSTATUS="OK"
					MSG="$(now)$MSG68"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi					
					echo "$MSG" >> "$TEMPLOG"
				else
					RESTARTSTATUS="ERRORE"
					MSG="$(now)$MSG69"
					if [ "$DEBUG" ]; then
						echo "$MSG"
					fi						
					echo "$MSG" >> "$TEMPLOG"
					# if there's been some error then log it and go on
					GUESTERROR="$GUESTERROR""\"""$GUESTNAME"\"" "
					THISGUESTOK="FALSE"
				fi				
			fi
		fi
	else
		## LVM=NO , STRATEGY=cold or VM already stopped/suspended
		## if the VM was powered off now we can archive it
		## echo to log (and to output if debug mode is enabled) that the archiving operation is starting
		backupvm "$GUESTNAME"
	fi
	## NOW IN ANY CASE THE VM HAS BEEN ARCHIVED
	
	##############################
	# HELP FILE CREATION
	##############################
	# create a small text file with the commands to merge the slices and restore the VM backup, just in case
	# there are also instructions on how to list the contents of the archive and how to simply merge the slices without extracting
	# lastly, there are some info on how to use the vmware-mount.pl command to mount the .VMDK files in a folder 
	# to extract one or more files without powering the VM up
	HELPFILE=""
	HELPFILE="$GUESTNAME""_instructions.txt"
	HELPTEXT=""
	# depending on which archival method has been chosen we customize the text message in the instructions
	if [ "$ARCHIVESUFFIX" == "tar" ]; then
		TEMPTEXT1="cat /path_to_backup_files/""$GUESTNAME"".""$ARCHIVESUFFIX""* | tar -xvf - \n"
		TEMPTEXT2="cat ""$GUESTNAME"".""$ARCHIVESUFFIX""* > ""$GUESTNAME"".""$ARCHIVESUFFIX"" \n"
	elif [ "$ARCHIVESUFFIX" == "tar.gz" ]; then
		TEMPTEXT1="cat /path_to_backup_files/""$GUESTNAME"".""$ARCHIVESUFFIX""* | tar -zxvf - \n"
		TEMPTEXT2="cat ""$GUESTNAME"".""$ARCHIVESUFFIX""* > ""$GUESTNAME"".""$ARCHIVESUFFIX"" \n"
	elif [ "$ARCHIVESUFFIX" == "tar.lzo" ]; then
		TEMPTEXT1="cat /path_to_backup_files/""$GUESTNAME"".""$ARCHIVESUFFIX""* | lzop -d | tar -xvf - \n"
		TEMPTEXT2="cat ""$GUESTNAME"".""$ARCHIVESUFFIX""* > ""$GUESTNAME"".""$ARCHIVESUFFIX"" \n"
	elif [ "$ARCHIVESUFFIX" == "tar.qp03" ]; then
		TEMPTEXT1="cat /path_to_backup_files/""$GUESTNAME"".""$ARCHIVESUFFIX""* | qpress -dc | tar -xvf - \n"
		TEMPTEXT2="cat ""$GUESTNAME"".""$ARCHIVESUFFIX""* > ""$GUESTNAME"".""$ARCHIVESUFFIX"" \n"	
	fi
	if [ "$ARCHIVESUFFIX" == "" ]; then
		TEMPTEXT3="Since the \"copy\" method has been selected there is no archive to extract \n"
		TEMPTEXT3="$TEMPTEXT3""and all the files that constitute the VM are ready, and you can then start it \n"
	else
		TEMPTEXT3="Once you have extracted the archive's contents in a folder you can then start the VM \n"
	fi
	if [ "$ARCHIVESUFFIX" != "" ]; then
		HELPTEXT="$HELPTEXT""To extract the archive's contents in the current directory \n"
		HELPTEXT="$HELPTEXT""you need to run the following command \n"
		HELPTEXT="$HELPTEXT""\n"
		HELPTEXT="$HELPTEXT""$TEMPTEXT1"
		HELPTEXT="$HELPTEXT""\n"
		HELPTEXT="$HELPTEXT""To merge the slices you need to run the following command \n"
		HELPTEXT="$HELPTEXT""\n"		
		HELPTEXT="$HELPTEXT""$TEMPTEXT2"
		HELPTEXT="$HELPTEXT""\n"
	fi
	HELPTEXT="$HELPTEXT""$TEMPTEXT3"
	HELPTEXT="$HELPTEXT""by opening VmWare Server console and chosing \"Open Existing Virtual Machine\" \n"
	HELPTEXT="$HELPTEXT""then browse the host to the folder where you extracted the VM files \n"
	HELPTEXT="$HELPTEXT""\n"	
	HELPTEXT="$HELPTEXT""now the VM is in the inventory and you can select it and, from the Snapshot menu \n"
	HELPTEXT="$HELPTEXT""you have to click \"Revert to Snapshot\" \n"
	HELPTEXT="$HELPTEXT""the VM will be restored to the exact moment and state when it was backed up \n"
	HELPTEXT="$HELPTEXT""\n"
	
	echo -e "$HELPTEXT" > "$BACKPATH"/"$HELPFILE"
	
	MSG="$(now)$MSG34A$HELPFILE$MSG34B"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi		
	echo "$MSG" >> "$TEMPLOG"
	
	# check the $THISGUESTOK variable, if it's  *not* FALSE it means there hasn't been any error
	if [ "$THISGUESTOK" != "FALSE" ] ; then
		GUESTOK="$GUESTOK""\""$GUESTNAME"\" "
		THISGUESTOK="TRUE"
	fi
	# the end (almost!)
	if [ "$THISGUESTOK" != "TRUE" ] ; then
		MSG="$(now)$MSG35$GUESTNAME"
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi	
		echo "$MSG" >> "$TEMPLOG"
	else
		MSG="$(now)$MSG36A$GUESTNAME$MSG36B"
		if [ "$DEBUG" ]; then
			echo "$MSG"
		fi		
		echo "$MSG" >> "$TEMPLOG"
	fi
done

# at the end of the main loop, verify if there have been errors and create the subject and body for the email report
# the variable $GUESTOK contains the names of the VM backed up successfully, and
# the variable $GUESTERROR contains the names of the VM with some errors
# if there have been both errors and successes, report "Backup incomplete"
if [ "$GUESTERROR" != "" ] && [ "$GUESTOK" != "" ]; then
	RESULT="$(now)$MSG37$GUESTERROR \n"
	RESULT="$RESULT""$(now)$MSG38A""$GUESTOK""$MSG38B"
	RESULT="$RESULT""$(now)$MSG39"
	echo -e "$RESULT" >> "$TEMPLOG"
	EMAILSUB="$MSG60"
	EMAILBODY="$RESULT"
# if no VM has been backed up successfully then report "Backup failed"
elif [ "$GUESTERROR" != "" ] && [ "$GUESTOK" == "" ] ; then
	RESULT="$(now)$MSG40$GUESTERROR \n"
	RESULT="$RESULT""$(now)$MSG41"
	echo -e "$RESULT" >> "$TEMPLOG"
	EMAILSUB="$MSG42"
	EMAILBODY="$RESULT"
# if all VM backed up successfully then report "Backup complete"
else
	RESULT="$(now)$MSG43A$GUESTOK$MSG43B"
	RESULT="$RESULT""$(now)$MSG44"
	echo -e "$RESULT" >> "$TEMPLOG"
	EMAILSUB="$MSG45"
	EMAILBODY="$RESULT"
fi

# if the EMAIL REPORT SETTINGS have been configured then send the email to the recipients and attach the log of this session 
if [ "$EMAILTO" != "youremail@yourdomain.com" ]; then
	"$SENDEMAIL" -f "$EMAILFROM" -t "$EMAILTO" -u "$EMAILSUB" -m "$EMAILBODY" -s "$EMAILSRV" -a "$TEMPLOG"
	MSG="$(now)$MSG46"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
else
	MSG="$(now)$MSG67"
	if [ "$DEBUG" ]; then
		echo "$MSG"
	fi	
	echo "$MSG" >> "$TEMPLOG"
fi	
	
# copies the $TEMPLOG to the $LASTLOG
cp "$TEMPLOG" "$LASTLOG"

# appends the log of this session to the cumulative log
cat "$LASTLOG" >> "$LOG"
MSG="$(now)$MSG47"
if [ "$DEBUG" ]; then
	echo "$MSG"
fi
# THE END